package com.product.annotation.aspect;

import com.common.ResultCode;
import com.product.annotation.AccessLimit;
import com.product.config.Exception.ServiceException;
import com.product.util.impl.RedisUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.Instant;

/**
 * @program: Member_Perks_Store
 * @description: 接口限流切面类
 * @author: 无恙
 * @create: 2024-06-18 08:15
 **/

@Aspect
@Scope
@Component
public class AccessLimitAspect {

    @Autowired
    private RedisUtil redisUtil;

    @Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(limit)")
    public void requestLimit(final JoinPoint joinPoint, AccessLimit limit) throws IOException {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr();
        String key = ip + ":" + request.getRequestURI();

        long currentTimeMillis = Instant.now().toEpochMilli();
        long expireTime = limit.time();

        String redisKey = key + ":" + (currentTimeMillis / expireTime);

        Long requestCount = redisUtil.incr(redisKey, 1);

        if (requestCount == 1) {
            redisUtil.expire(redisKey, expireTime);
        }

        if (requestCount > limit.count()) {
            throw new ServiceException(ResultCode.REQUEST_TOO_MANY);
        }

    }

}
